Coverage Report

Created: 2026-08-07 16:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\cssh-rs\cssh-rs\xtask\src\cross_build\strategy\windows_msvc.rs
Line
Count
Source
1
//! Windows-MSVC build orchestration.
2
//!
3
//! On Windows hosts, dispatches to native `cargo build`. On Linux and
4
//! macOS hosts, delegates to [`cargo-xwin`], which fetches the MSVC
5
//! CRT and Windows SDK on first use under the Microsoft Software
6
//! License Terms; this xtask sets `XWIN_ACCEPT_LICENSE=1` on the
7
//! cargo-xwin subprocess only after printing a notice.
8
//!
9
//! [`cargo-xwin`]: https://github.com/rust-cross/cargo-xwin
10
11
use anyhow::{bail, Result};
12
13
use super::super::ensure_rust_target_installed;
14
use super::super::system::windows_msvc::WindowsMsvcSystem;
15
use super::super::system::CrossBuildSystem;
16
17
pub const TRIPLE: &str = "x86_64-pc-windows-msvc";
18
19
/// Build cssh-rs for `x86_64-pc-windows-msvc`.
20
///
21
/// # Arguments
22
/// * `system` - Injected I/O provider.
23
/// * `release` - When true, build with `--release`; otherwise debug.
24
///
25
/// # Errors
26
/// Returns an error if the host is not supported, a prerequisite
27
/// install fails, or the build subprocess fails.
28
10
pub fn build<S: WindowsMsvcSystem>(system: &S, release: bool) -> Result<()> {
29
10
    let host = system.host_os();
30
    // Decide up front whether this (host, target) pair is supported
31
    // so we do not run a network-touching `rustup target add` against
32
    // a host we cannot finish the build on anyway.
33
10
    let 
path9
= match host {
34
10
        "windows" => 
BuildPath::Native3
,
35
7
        "linux" | 
"macos"2
=>
BuildPath::CargoXwin6
,
36
1
        _ => bail!("cross-build {TRIPLE} from {host} host is not supported by this xtask yet"),
37
    };
38
9
    ensure_rust_target_installed(system, TRIPLE)
?0
;
39
9
    match path {
40
3
        BuildPath::Native => build_native(system, release),
41
6
        BuildPath::CargoXwin => build_via_xwin(system, host, release),
42
    }
43
10
}
44
45
enum BuildPath {
46
    Native,
47
    CargoXwin,
48
}
49
50
3
fn build_native<S: WindowsMsvcSystem>(system: &S, release: bool) -> Result<()> {
51
3
    log::info!(
52
        "Running `cargo build {}--target {TRIPLE}`",
53
0
        if release { "--release " } else { "" }
54
    );
55
3
    system.run_cargo_build(TRIPLE, release)
56
3
}
57
58
6
fn build_via_xwin<S: WindowsMsvcSystem>(system: &S, host: &str, release: bool) -> Result<()> {
59
6
    ensure_llvm_tooling_available(system, host)
?1
;
60
5
    ensure_cargo_xwin_installed(system)
?0
;
61
5
    log::info!(
62
        "Invoking cargo-xwin with XWIN_ACCEPT_LICENSE=1 to accept the \
63
         Microsoft Software License Terms for the MSVC CRT and Windows SDK. \
64
         cargo-xwin downloads them into your local cache on first use; \
65
         nothing is checked into this repository."
66
    );
67
5
    log::info!(
68
        "Running `cargo xwin build {}--target {TRIPLE}`",
69
0
        if release { "--release " } else { "" }
70
    );
71
5
    system.run_cargo_xwin_build(TRIPLE, release)
72
6
}
73
74
/// Verify that the LLVM tools cargo-xwin and embed-resource need are
75
/// available; do not auto-install (the package manager needs sudo /
76
/// admin, which the xtask must not silently assume).
77
6
fn ensure_llvm_tooling_available<S: CrossBuildSystem>(system: &S, host: &str) -> Result<()> {
78
    // `llvm-rc` is the load-bearing one: `embed-resource` invokes it
79
    // to compile the Windows .rc file. `clang` and `lld-link` are
80
    // exercised by cargo-xwin's compile/link stages.
81
6
    let missing: Vec<&str> = ["llvm-rc", "clang", "lld-link"]
82
6
        .into_iter()
83
18
        .
filter6
(|tool| !system.is_executable_in_path(tool))
84
6
        .collect();
85
6
    if missing.is_empty() {
86
5
        log::info!("LLVM tooling (llvm-rc, clang, lld-link) found in PATH");
87
5
        return Ok(());
88
1
    }
89
1
    let hint = match host {
90
1
        "linux" => concat!(
91
            "install via your distro's package manager, for example ",
92
            "`sudo apt install clang llvm lld` on Debian/Ubuntu or ",
93
            "`sudo dnf install clang llvm lld` on Fedora",
94
        ),
95
0
        "macos" => concat!(
96
            "install via Homebrew: `brew install llvm` and ensure its ",
97
            "`bin/` directory is on PATH",
98
        ),
99
0
        _ => concat!(
100
            "install LLVM 14+ via your OS package manager and ensure ",
101
            "llvm-rc, clang, and lld-link are on PATH",
102
        ),
103
    };
104
1
    bail!(
105
        "cargo-xwin needs LLVM tooling that is not in PATH: {}. {hint}.",
106
1
        missing.join(", ")
107
    );
108
6
}
109
110
5
fn ensure_cargo_xwin_installed<S: WindowsMsvcSystem>(system: &S) -> Result<()> {
111
5
    let listed = system.list_cargo_subcommands()
?0
;
112
    // `cargo --list` formats each external command as
113
    // `    <name>                 <description>` on its own line.
114
5
    let has_xwin = listed
115
5
        .lines()
116
12
        .
any5
(|line| line.split_whitespace().next() == Some("xwin"));
117
5
    if has_xwin {
118
4
        log::info!("cargo-xwin already installed");
119
    } else {
120
1
        let version = system.read_cargo_xwin_version()
?0
;
121
1
        log::info!("Installing cargo-xwin {version}");
122
1
        system.install_cargo_subcommand("cargo-xwin", &version)
?0
;
123
    }
124
5
    Ok(())
125
5
}